package com.peng.mybatis.executor;

import cn.hutool.core.lang.Assert;
import com.peng.mybatis.mapping.BoundSql;
import com.peng.mybatis.mapping.MappedStatement;
import com.peng.mybatis.session.Configuration;
import com.peng.mybatis.session.ResultHandler;
import com.peng.mybatis.transaction.Transaction;
import lombok.extern.slf4j.Slf4j;

import java.sql.SQLException;
import java.util.List;

@Slf4j
public abstract class BaseExecutor implements Executor {

    protected Configuration configuration;

    protected Transaction transaction;

    protected Executor wrapper;

    private boolean closed;

    public BaseExecutor(Configuration configuration,
                        Transaction transaction) {
        this.configuration = configuration;
        this.transaction = transaction;
        this.wrapper = this;
    }

    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter, ResultHandler resultHandler, BoundSql boundSql) {
        checkClose();
        return doQuery(ms, parameter, resultHandler, boundSql);
    }

    protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, ResultHandler resultHandler, BoundSql boundSql);

    @Override
    public Transaction getTransaction() {
        checkClose();
        return transaction;
    }

    @Override
    public void commit(boolean required) throws SQLException {
        checkClose();
        if (required) {
            transaction.commit();
        }
    }

    @Override
    public void rollback(boolean required) throws SQLException {
        checkClose();
        if (required) {
            transaction.rollback();
        }
    }

    @Override
    public void close(boolean forceRollback) {
        try {
            try {
                rollback(forceRollback);
            } catch (SQLException e) {
                transaction.close();
            }
        } catch (SQLException e) {
            log.warn("关闭事务失败：{}", e.getMessage());
        } finally {
            transaction = null;
            closed = true;
        }
    }

    protected void checkClose() {
        Assert.isFalse(closed, "执行器已经关闭！");
    }

}
